Skip to content

feat(multi-repo): 多根工作区仓库切换(Graph 选择器 + 全局活跃仓库级联,issue #107) - #108

Merged
ThreeFish-AI merged 10 commits into
feature/1.x.xfrom
ThreeFish-AI/issue-107-feasibility-analysis
Aug 20, 2026
Merged

feat(multi-repo): 多根工作区仓库切换(Graph 选择器 + 全局活跃仓库级联,issue #107)#108
ThreeFish-AI merged 10 commits into
feature/1.x.xfrom
ThreeFish-AI/issue-107-feasibility-analysis

Conversation

@ThreeFish-AI

@ThreeFish-AI ThreeFish-AI commented Aug 20, 2026

Copy link
Copy Markdown
Owner

概述

closes #107 —— 多根工作区(multi-root)含多个 Git 仓库时无法切换仓库:GitRepositoryService.pickRepository() 只锁定首个 folder 匹配或 repositories[0],且 changelist/收藏/分组/Shelf 等 4 处构造期冻结的按仓库持久化状态不随仓库变化。本 PR 落地全局活跃仓库切换(Git Graph 模式),一次切换全视图级联跟随。

变更内容

用户可见

  • Graph 工具栏仓库名升级为可切换按钮:多仓库态显示 basename ▾、hover 高亮,点击弹原生 QuickPick;单仓库退化为纯文本观感(多数用户零感知);
  • Hyper Git: Select Repository… palette 命令(当前仓库预选;单仓库提示 no-op);
  • 七个视图级联跟随:Graph / Branches / Commit(changelist)/ Stash / Shelf / Worktrees / 未提交角标;
  • 按仓库隔离记忆:changelist 分配、分支收藏、分支分组偏好、Shelf 存储、最近提交消息、Graph/Commit webview 视图状态(scope/选中/勾选集);重开窗口恢复上次活跃仓库(workspaceState: hyperGit.activeRepoRoot)。

实现要点

  • 选取逻辑下沉纯函数 engine/git-state/repo-selection.ts持久化恢复 → folder0 匹配 → 首个仓库三级优先;路径归一化去尾分隔符 + win32 大小写不敏感,跨平台稳定);
  • 三重顺序不变量保证 rebind 先于视图刷新:applyRepository 内先 fire onDidChangeRepository(同步 rebind:换 memento key / 重载 / context key 同步 / Blame 清理 / Graph filter 清空)后 fire onDidChange(150ms 防抖刷新),且 rebind 订阅先注册;
  • Shelf 目录随 service.repoRoot 动态求值shelves/<basename>.<sha1[:8]>/,零快照零双源),旧平铺数据一次性安全迁移:仅 rename(零删除)、目标已存在即跳过(零覆盖)、失败可重试;
  • Blame 注解切库自清理;顺带修复既有激活竞态(repo 发现晚于 activate 时 memento key 落 workspaceRoot 占位,现由 rebind 事件纠正);
  • @vscode/test-electron 3.0.0 → 3.1.0:VS Code 1.110 起将 macOS 主二进制 Electron 更名 Code(兼容符号链接已移除),3.0.0 启动 1.110+ 即 ENOENT 崩溃;即 PR chore(deps-dev): bump @vscode/test-electron from 3.0.0 to 3.1.0 #102 因 supply-chain 发布冷静期被拦的版本,窗口已过。

验证

  • pnpm run compile(check-types + lint + esbuild)通过;
  • 单元测试 403/403(新增 42:repo-selection 13 + 归一化 2 / shelf-dir 6 / 三处 setRepoRoot 隔离与幂等 17+4);
  • 集成测试 12/12:单仓库回归 8(行为与旧版完全一致)+ 新增 multi-root 双仓库套件 4(activate() 导出 { service } 程序化切换接缝,repoA⇄repoB 断言 repoRoot 跟随、切换后全 refresh 不抛错、不存在路径返回 false)。

完整设计文档(交互形态 mermaid、时序图、状态隔离矩阵、Shelf 迁移流程):docs/features/multi-root-repo-selection.md

🤖 Generated with Claude Code

- pickRepositoryRoot:持久化恢复 → 首个 folder 匹配(可注入 getRepository 语义,
  缺省最长祖先匹配)→ 首个仓库 的三级优先选取,路径归一化(去尾分隔符 +
  win32 大小写不敏感)保证跨平台稳定比较;
- shelfRepoDirName:basename 截 48 字符 + sha1 前 8 位生成按仓库隔离的
  shelf 存储子目录名,防同名仓库碰撞;
- 配套 19 个单测(选取优先级/归一化/碰撞/截断/兜底)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- 新增 onDidChangeRepository 事件与 selectRepository/listRepositories API,
  选取逻辑下沉 engine(pickRepositoryRoot 三级优先级:持久化恢复 → 首个 folder
  匹配 → 首个仓库),活跃仓库持久化于 workspaceState(hyperGit.activeRepoRoot,
  last-active 语义,重开窗口回到上次操作的仓库);
- applyRepository 编码顺序不变量:切换事件(同步 rebind)先于 onDidChange
  (防抖刷新)fire;顺带修复激活竞态——repo 发现晚于 activate 时由 rebind 纠正;
- extension.ts 装配级联:registry/favorites/branchesTree setRepoRoot + branchesGrouping
  context key 同步(原仅 activate 设置一次);
- activate 返回 { service } 供集成测试程序化驱动(vscode.git 同款导出模式);
- Blame 注解订阅仓库切换自清理(旧仓库 blame 数据不再残留编辑器)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- ChangelistRegistry/BranchFavorites/BranchesTreeProvider 三处构造期冻结的
  memento key(hyperGit.changelists/branchFavorites/branchesGrouping:${repoRoot})
  改为可重绑:同构「幂等守卫 → 换 key → 重载 → fire/refresh」模式;
- 单测:EventEmitter mock 升级为功能性实现(fire 通知监听);新增跨仓库隔离、
  同 root 幂等、切换后 persist 写入新 key 等用例(16 个)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- 目录改为 shelves/<basename>.<sha1 前 8 位>/,随 service.repoRoot 动态求值
  (零快照零双源),切换仓库即切换 shelf 集,杜绝 A 库 shelf 误 apply 到 B 库;
- migrateLegacyShelves 一次性迁移:仅 rename(零删除)、目标已存在即跳过
  (零覆盖)、失败静默可重试(已移入保留、未移入下次续迁);
- 多仓库历史混仓数据归属当前活跃仓库(无法事后归因,已列 Known Limitation)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- 协议:LogWebviewToHostMessage 新增 log/selectRepo(webview→host),
  LogGraphState 新增可选 multiRepo(向后兼容);
- 工具栏仓库名升级为可点击按钮(Git Graph 形态):多仓库态显示 basename+▾、
  hover 高亮、点击弹原生 QuickPick;单仓库退化纯文本观感(多数用户零感知);
- 新增 hyperGit.selectRepository 命令(palette 入口):带参=程序化切换(测试
  接缝),无参=QuickPick(当前项预选);单仓库提示 no-op,零仓库静默;
- host 级 LogFilter 在仓库切换时清空(过滤条件是旧仓库语境产物,跨库无意义)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- Graph webview:vscode.getState() 升级 v2 byRepo 结构(scope/选中/dmode/
  dcollapsed 跟随仓库换装载),旧平铺结构一次性升级不丢偏好;host 侧 scope
  内存级按仓库记忆,切回仓库恢复其视图范围;
- Commit webview:勾选集/视图模式同模式按仓库分区(勾选是相对路径集合,
  跨仓库本就错位);CommitViewState 新增 repoRoot 字段;
- 最近提交消息改 per-repo key(hyperGit.recentCommitMessages:${repoRoot}),
  未命中回落旧全局 key 一次(平滑迁移,不删旧数据)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- run-integration.js 新增 createFixtureWorkspace():repo-a/repo-b 双独立仓库
  + multi-root.code-workspace,在既有单仓库套件后顺序追加第二段 VS Code 启动;
- multi-root.test.js:命令注册冒烟、程序化切换(activate 导出 { service } 接缝)
  repoA⇄repoB 断言 repoRoot 跟随 + 切换后 refreshLog/refreshBranches/refresh
  不抛错、不存在路径返回 false 不炸、listRepositories 双仓库;
- extension.test.js 命令断言追加 hyperGit.selectRepository。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
VS Code 1.110 起将 macOS 主二进制 Electron 更名为 Code(兼容符号链接已于
2026-07 移除,microsoft/vscode#326502),3.0.0 启动 1.110+ 归档即
spawn .../MacOS/Electron ENOENT 崩溃;3.1.0 按 Info.plist →
CFBundleExecutable 三级解析修复(microsoft/vscode-test#348)。此前
dependabot PR #102 因 supply-chain 发布冷静期被 CI 拦截,现窗口已过正式合入。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- 新增 docs/features/multi-root-repo-selection.md:交互形态、三重顺序不变量
  时序图、选取优先级、按仓库隔离状态矩阵、Shelf 迁移与集成测试说明;
- knowledge-map 索引新文档;issue.md 追加 #107 条目(表因/根因/处理/防范:
  快照 repoRoot 的新组件必须订阅 onDidChangeRepository 重绑);
- CHANGELOG Unreleased 记录特性与 test-electron 升级;README 双语指标行
  同步(101→102 命令、375→403 单测)+ Features 补多根切换条目。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI ThreeFish-AI changed the title feat(multi-repo): 多根工作区仓库切换——Graph 工具栏选择器与全局活跃仓库级联(issue #107) feat(multi-repo): 多根工作区仓库切换(Graph 选择器 + 全局活跃仓库级联,issue #107) Aug 20, 2026
- log-webview 三条异步取数链路(fetchPage/sendCommitFiles/showCommitDetail)增加切库竞态守卫:锁定发起时刻的 repoRoot,execGit 期间发生切换即丢弃结果,防止旧仓库的 appendData/commitFiles/commitDetail 迟到响应污染新仓库视图;
- git-repository-service 的 dispose 补释放 _onDidChangeRepository emitter,消除监听器引用泄漏。

🤖 Generated with [Claude Code](https://github.com/claude.com), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI
ThreeFish-AI merged commit b999864 into feature/1.x.x Aug 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant